home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / elv18src.zip / unix.c < prev    next >
C/C++ Source or Header  |  1994-01-10  |  5KB  |  240 lines

  1. /* unix.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains the unix-specific versions the ttyread() functions.
  12.  * There are actually three versions of ttyread() defined here, because
  13.  * BSD, SysV, and V7 all need quite different implementations.
  14.  */
  15.  
  16. #include "config.h"
  17. #if ANY_UNIX || OS2
  18. # include "vi.h"
  19.  
  20. # if BSD && !TERMIOS
  21. /* For BSD, we use select() to wait for characters to become available,
  22.  * and then do a read() to actually get the characters.  We also try to
  23.  * handle SIGWINCH -- if the signal arrives during the select() call, then
  24.  * we adjust the o_columns and o_lines variables, and fake a control-L.
  25.  */
  26. #  include <sys/types.h>
  27. #  include <sys/time.h>
  28. int ttyread(buf, len, time)
  29.     char    *buf;    /* where to store the gotten characters */
  30.     int    len;    /* maximum number of characters to read */
  31.     int    time;    /* maximum time to allow for reading */
  32. {
  33.     fd_set    rd;    /* the file descriptors that we want to read from */
  34.     static    tty;    /* 'y' if reading from tty, or 'n' if not a tty */
  35.     int    i;
  36.     struct timeval t;
  37.     struct timeval *tp;
  38.  
  39.  
  40.     /* do we know whether this is a tty or not? */
  41.     if (!tty)
  42.     {
  43.         tty = (isatty(0) ? 'y' : 'n');
  44.     }
  45.  
  46.     /* compute the timeout value */
  47.     if (time)
  48.     {
  49.         t.tv_sec = time / 10;
  50.         t.tv_usec = (time % 10) * 100000L;
  51.         tp = &t;
  52.     }
  53.     else
  54.     {
  55.         tp = (struct timeval *)0;
  56.     }
  57.  
  58.     /* loop until we get characters or a definite EOF */
  59.     for (;;)
  60.     {
  61.         if (tty == 'y')
  62.         {
  63.             /* wait until timeout or characters are available */
  64.             FD_ZERO(&rd);
  65.             FD_SET(0, &rd);
  66.             i = select(1, &rd, (fd_set *)0, (fd_set *)0, tp);
  67.         }
  68.         else
  69.         {
  70.             /* if reading from a file or pipe, never timeout!
  71.              * (This also affects the way that EOF is detected)
  72.              */
  73.             i = 1;
  74.         }
  75.     
  76.         /* react accordingly... */
  77.         switch (i)
  78.         {
  79.           case -1:    /* assume we got an EINTR because of SIGWINCH */
  80.             if (*o_lines != LINES || *o_columns != COLS)
  81.             {
  82. #ifndef CRUNCH
  83.                 *o_nearscroll = 
  84. #endif
  85.                 *o_lines = LINES;
  86.                 *o_columns = COLS;
  87.                 if (mode != MODE_EX)
  88.                 {
  89.                     /* pretend the user hit ^L */
  90.                     *buf = ctrl('L');
  91.                     return 1;
  92.                 }
  93.             }
  94.             break;
  95.     
  96.           case 0:    /* timeout */
  97.             return 0;
  98.     
  99.           default:    /* characters available */
  100.             return read(0, buf, len);
  101.         }
  102.     }
  103. }
  104. # else
  105.  
  106. # if UNIXV || COH_386 || OS2 || TERMIOS
  107. /* For System-V, we use VMIN/VTIME to implement the timeout.  For no timeout,
  108.  * VMIN should be 1 and VTIME should be 0; for timeout, VMIN should be 0 and
  109.  * VTIME should be the timeout value.
  110.  */
  111. #  if TERMIOS
  112. #   include <termios.h>
  113. #  else
  114. #   include <termio.h>
  115. #  endif
  116. int ttyread(buf, len, time)
  117.     char    *buf;    /* where to store the gotten characters */
  118.     int    len;    /* maximum number of characters to read */
  119.     int    time;    /* maximum time to allow for reading */
  120. {
  121. #   if TERMIOS
  122.     struct termios tio;
  123. #   else
  124.     struct termio tio;
  125. #   endif
  126.     int    bytes;    /* number of bytes actually read */
  127.  
  128.     /* arrange for timeout */
  129. #   if TERMIOS
  130.     tcgetattr(0, &tio);
  131. #   else
  132.     ioctl(0, TCGETA, &tio);
  133. #   endif
  134.     if (time)
  135.     {
  136.         tio.c_cc[VMIN] = 0;
  137.         tio.c_cc[VTIME] = time;
  138.     }
  139.     else
  140.     {
  141.         tio.c_cc[VMIN] = 1;
  142.         tio.c_cc[VTIME] = 0;
  143.     }
  144. #   if TERMIOS
  145.     tcsetattr(0, TCSANOW, &tio);
  146. #   else
  147.     ioctl(0, TCSETA, &tio);
  148. #   endif
  149.  
  150.     /* Perform the read.  Loop if EINTR error happens */
  151.     while ((bytes = read(0, buf, (unsigned)len)) < 0)
  152.     {
  153.         /* probably EINTR error because a SIGWINCH was received */
  154.         if (*o_lines != LINES || *o_columns != COLS)
  155.         {
  156.             *o_lines = LINES;
  157.             *o_columns = COLS;
  158.             if (mode != MODE_EX)
  159.             {
  160.                 /* pretend the user hit ^L */
  161.                 *buf = ctrl('L');
  162.                 return 1;
  163.             }
  164.         }
  165.     }
  166.  
  167. #if OS2
  168.     {
  169.         int cnt;
  170.         for (cnt = 0; cnt < bytes; cnt++)
  171.         {
  172.             /* extended key, scan code follows */
  173.             if (buf[cnt] == 0)
  174.             {
  175.                 buf[cnt] = '#';
  176.             }
  177.         }
  178.     }
  179. #endif
  180.  
  181.     /* return the number of bytes read */
  182.     return bytes;
  183.  
  184.     /* NOTE: The terminal may be left in a timeout-mode after this function
  185.      * returns.  This shouldn't be a problem since Elvis *NEVER* tries to
  186.      * read from the keyboard except through this function.
  187.      */
  188. }
  189.  
  190. # else /* any other version of UNIX, assume it is V7 compatible */
  191.  
  192. /* For V7 UNIX (including Minix) we set an alarm() before doing a blocking
  193.  * read(), and assume that the SIGALRM signal will cause the read() function
  194.  * to give up.
  195.  */
  196.  
  197. #include <setjmp.h>
  198.  
  199. static jmp_buf env;
  200.  
  201. /*ARGSUSED*/
  202. SIGTYPE dummy(signo)
  203.     int    signo;
  204. {
  205.     longjmp(env, 1);
  206. }
  207. int ttyread(buf, len, time)
  208.     char    *buf;    /* where to store the gotten characters */
  209.     int    len;    /* maximum number of characters to read */
  210.     int    time;    /* maximum time to allow for reading */
  211. {
  212.     /* arrange for timeout */
  213.     signal(SIGALRM, dummy);
  214.     alarm(time);
  215.  
  216.     /* perform the blocking read */
  217.     if (setjmp(env) == 0)
  218.     {
  219.         len = read(0, buf, (unsigned)len);
  220.     }
  221.     else /* I guess we timed out */
  222.     {
  223.         len = 0;
  224.     }
  225.  
  226.     /* cancel the alarm */
  227.     signal(SIGALRM, dummy); /* <-- to work around a bug in Minix */
  228.     alarm(0);
  229.  
  230.     /* return the number of bytes read */
  231.     if (len < 0)
  232.         len = 0;
  233.     return len;
  234. }
  235.  
  236. # endif /* M_SYSV */
  237. # endif /* !BSD */
  238.  
  239. #endif /* ANY_UNIX */
  240.